#ifndef __System_Type_Core_H__
#define __System_Type_Core_H__

///<summary>
/// Type
///</summary>
enum {
	_TypeFlags_None = 0,
	_TypeFlags_Interface = 1,
	_TypeFlags_Value = 2,
};
typedef System_Object *(*__typeBoxer)(int value);
typedef int (*__typeUnboxer)(System_Object *value);
typedef void *(*__typeCtor)(void *p, void *t);
typedef struct rSystem_Type {
	public __typeCtor __ctor;
	public string Name;
	public __typeBoxer __boxer;
	public __typeUnboxer __unboxer;
	public char *__default;
	public int __flags;
} System_Type;

///<summary>
/// Implement_Type
///</summary>
#define Implement_Type(T,Tbase,typeInterfaces,...) \
	private_ void *_##T##TypeCtor(System_Object *p, T *t) \
	{ \
		/*printf("%s __ctor(0x%08x, 0x%08x)\n", #T, p, t);*/ \
		t->__parent = p; \
		t->__next = (System_Object *)null; \
		if (p != null) p->__next = (System_Object *)t; \
		__typeBinder2(t,__getBase(t,Tbase),typeof(Tbase)); \
		t->__interfaces = null; \
		typeInterfaces \
		{ __VA_ARGS__ } \
		return t; \
	} \
	System_Type _##T##Type = { (__typeCtor)&_##T##TypeCtor, L#T, (__typeBoxer)&___boxobject, (__typeUnboxer)&___unboxobject, (char*)null, _TypeFlags_None };
#define Implement_TypeT(T,T2,Tbase,typeInterfaces,...) \
	private_ void *_##T##_##T2##TypeCtor(System_Object *p, T##_##T2 *t) \
	{ \
		t->__parent = p; \
		t->__next = (System_Object *)null; \
		if (p != null) p->__next = (System_Object *)t; \
		__typeBinder2(t,__getBase(t,Tbase),typeof(Tbase)); \
		t->__interfaces = null; \
		typeInterfaces \
		{ __VA_ARGS__ } \
		return t; \
	} \
	System_Type _##T##_##T2##Type = { (__typeCtor)&_##T##_##T2##TypeCtor, L#T L"<" L#T2 L">", (__typeBoxer)&___boxobject, (__typeUnboxer)&___unboxobject, (char*)null, _TypeFlags_None };
#define Implement_TypeV(T,Tbase,typeInterfaces,...) \
	private_ void *_##T##TypeCtor(System_Object *p, T *t) \
	{ \
		System_ObjectVector *vtable = t->__vtable; \
		/*printf("%s __ctorV(0x%08x, 0x%08x)\n", #T, p, t);*/ \
		t->__parent = p; \
		t->__next = (System_Object *)null; \
		if (p != null) p->__next = (System_Object *)t; \
		__typeBinder2(t,__getBase(t,Tbase),typeof(Tbase)); \
		t->__interfaces = null; \
		typeInterfaces \
		{ __VA_ARGS__ } \
		return t; \
	} \
	System_Type _##T##Type = { (__typeCtor)&_##T##TypeCtor, L#T, (__typeBoxer)&___boxobject, (__typeUnboxer)&___unboxobject, (char*)null, _TypeFlags_None  };
#define Implement_TypeTV(T,T2,Tbase,typeInterfaces,...) \
	private_ void *_##T##_##T2##TypeCtor(System_Object *p, T##_##T2 *t) \
	{ \
		System_ObjectVector *vtable = t->__vtable; \
		/*printf("%s __ctorV(0x%08x, 0x%08x)\n", #T, p, t);*/ \
		t->__parent = p; \
		t->__next = (System_Object *)null; \
		if (p != null) p->__next = (System_Object *)t; \
		__typeBinder2(t,__getBase(t,Tbase),typeof(Tbase)); \
		t->__interfaces = null; \
		typeInterfaces \
		{ __VA_ARGS__ } \
		return t; \
	} \
	System_Type _##T##_##T2##Type = { (__typeCtor)&_##T##_##T2##TypeCtor, L#T L"<"L#T2 L">", (__typeBoxer)&___boxobject, (__typeUnboxer)&___unboxobject, (char*)null, _TypeFlags_None };
#define Implement_TypeI(T,typeInterfaces,...) \
	T *space(T,ctor)(T *t) { return t; } \
	private_ void *_##T##TypeCtor(System_Object *p, T *t) \
	{ \
		/*printf("%s __ctorI(0x%08x, 0x%08x)\n", #T, p, t);*/ \
		t->__parent = p; \
		t->__next = (System_Object *)null; \
		/*__typeBinder2(t,__getBase(t,System_Object),typeof(System_Object));*/ \
		typeInterfaces \
		memset(t->__vtable, 0, _##T##VIndexNext); \
		{ __VA_ARGS__ } \
		space(T,ctor)(t); \
		return t; \
	} \
	System_Type _##T##Type = { (__typeCtor)&_##T##TypeCtor, L#T, (__typeBoxer)&___boxobject, (__typeUnboxer)&___unboxobject, (char*)null, _TypeFlags_Interface };
#define Implement_TypeTI(T,T2,typeInterfaces,...) \
	T##_##T2 *space(T##_##T2,ctor)(T##_##T2 *t) { return t; } \
	private_ void *_##T##_##T2##TypeCtor(System_Object *p, T##_##T2 *t) \
	{ \
		/*printf("%s __ctorI(0x%08x, 0x%08x)\n", #T, p, t);*/ \
		t->__parent = p; \
		t->__next = (System_Object *)null; \
		/*__typeBinder2(t,__getBase(t,System_Object),typeof(System_Object));*/ \
		typeInterfaces \
		memset(t->__vtable, 0, _##T##_##T2##VIndexNext); \
		{ __VA_ARGS__ } \
		space(T##_##T2,ctor)(t); \
		return t; \
	} \
	System_Type _##T##_##T2##Type = { (__typeCtor)&_##T##_##T2##TypeCtor, L#T L"<"L#T2 L">", (__typeBoxer)&___boxobject, (__typeUnboxer)&___unboxobject, (char*)null, _TypeFlags_Interface };

///<summary>
/// typeInterface
///</summary>
#define typeInterface(A) t->__interfaces=__typeInterfaceBinder(t,&t->A.__type,typeof(A));
#define typeInterface2(A,B) t->__interfaces=__typeInterfaceBinder(t,__typeInterfaceBinder(t,&t->A.__type,typeof(B)),typeof(A));
#define typeInterface3(A,B,C) t->__interfaces=__typeInterfaceBinder(t,__typeInterfaceBinder(t,__typeInterfaceBinder(t,&t->A.__type,typeof(C)),typeof(B)),typeof(A));
#define typeInterface4(A,B,C,D) t->__interfaces=__typeInterfaceBinder(t,__typeBinder2(t,__typeInterfaceBinder(t,__typeInterfaceBinder(t,&t->A.__type,t,typeof(D)),typeof(C)),typeof(B)),typeof(A));

///<summary>
/// Ctor
///</summary>
#define __getBase(t,T) (T *)&(t->T.__type)
#define baseCtor(n,t,T,...) \
	(void *)T##_ctor##n(__getBase(t,T),__VA_ARGS__);
#define thisCtor baseCtor
//+ binder
__forceinline __device__ void *__typeBinder(void *t, System_Type *type)
{
	((System_Object *)t)->__type = type;
	type->__ctor(null,t);
	return(t);
}
__forceinline __device__ void *__typeBinder2(void *p, void *t, System_Type *type)
{
	((System_Object *)t)->__type = type;
	type->__ctor(p,t);
	return(t);
}
__forceinline __device__ void *__typeInterfaceBinder(void *p, void *t, System_Type *type)
{
	if ((type->__flags & _TypeFlags_Interface) != _TypeFlags_Interface)
	{
		throw(NotAnInterface);
	}
	((System_Object *)t)->__type = type;
	type->__ctor(p,t);
	return(t);
}
///<summary>
/// Implement_Ctor
///</summary>
#define Implement_Ctor(n,T,body,...) \
	T *space(T,ctor##n)(T *t,__VA_ARGS__) \
	{	body \
		return t; \
	}
#define Implement_CtorT(n,T,T2,body,...) \
	bindT(T,T2) *spaceT(T,T2,ctor##n)(bindT(T,T2) *t,__VA_ARGS__) \
	{	body \
		return t; \
	}
#define Implement_DefaultCtor(T,Tbase) \
	T *space(T,ctor)(T *t) \
	{	baseCtor(,t,Tbase); \
		return t; \
	}
#define Implement_DefaultCtorT(T,T2,Tbase) \
	bindT(T,T2) *spaceT(T,T2,ctor)(bindT(T,T2) *t) \
	{	baseCtor(,t,Tbase); \
		return t; \
	}

extern __device__ System_Type _System_ObjectType;
public __device__ System_Object *_getInstanceByType(System_Object *obj, System_Type *type, bool throwOnNull, void **_ref);
//+ binder
__forceinline __device__ System_ObjectVector __vcallBinder(System_Object *t, System_Type *type, unsigned long vtableOffset, int methodIndex, void **_ref)
{
	System_Object *obj;
	System_Type *tType = t->__type;
	if (tType == type)
	{
		obj = t;
		*_ref = ((tType->__flags & _TypeFlags_Interface) != _TypeFlags_Interface ? t : t->__parent);
	} else {
		obj = _getInstanceByType(t, type, true, _ref);
	}
	return ((System_ObjectVector *)(((char*)obj)+vtableOffset))[methodIndex];
}

#endif /* __System_Type_Core_H__ */
